home *** CD-ROM | disk | FTP | other *** search
- /* Post Office Protocol (POP3) Client -- RFC1460
- * Copyright 1992 William Allen Simpson
- * based on a POP2 Client by Mike Stockett, WA7DYX, et alia.
- * Aug 94 ported to WNOS by DG1ZX
- */
- #include <stdio.h>
- #include <fcntl.h>
- #include <time.h>
- #include <setjmp.h>
- #ifdef UNIX
- #include <sys/types.h>
- #endif
- #ifdef __TURBOC__
- #include <dir.h>
- #include <io.h>
- #endif
- #include "global.h"
- #include "config.h"
-
- #ifdef POP3_CLIENT
-
- #ifdef ANSIPROTO
- #include <stdarg.h>
- #endif
- #include "mbuf.h"
- #include "cmdparse.h"
- #include "proc.h"
- #include "socket.h"
- #include "timer.h"
- #include "netuser.h"
- #include "dirutil.h"
- #include "files.h"
- #include "smtp.h"
-
-
- /* mail separator */
- #define isNotSOM(x) ((strncmp(x,"From ",5) != 0))
-
- #define BUF_LEN 512
-
- /* POP3 client control block */
- static struct pop3_ccb {
- int socket; /* socket for this connection */
- char state; /* client state */
- #define CALL 0
- #define PASS 1
- #define STAT 2
- #define XFER 3
- #define RETR 4
- #define DELE 5
- #define ERROR 9
- #define EXIT 10
- char buf[BUF_LEN]; /* tcp input buffer pointer */
- int messages; /* number of msgs in current folder */
- int msg_no; /* current message number */
- long bytes; /* folder size */
- } *ccb;
- #define NULLCCB (struct pop3_ccb *)0
-
- static int16 Popquiet = 0;
- static int32 mailhost = 0;
-
- static void pop_send __ARGS((int unused,void *cb1,void *p));
- static int poptick __ARGS((void));
- static int copymail __ARGS((char *spoolarea,char *filename,char *buf,unsigned len,FILE *wfp));
- static int recvmail __ARGS((struct pop3_ccb *cp,FILE *fp));
-
-
- /* Command string specifications */
- static char near mailbox_name[20],
- username[20],
- password[20],
- Workfile_name[] = "mbox3.pop",
- user_cmd[] = "USER %s\n",
- pass_cmd[] = "PASS %s\n",
- stat_cmd[] = "STAT\n",
- retr_cmd[] = "RETR %d\n",
- del_cmd[] = "DELE %d\n",
- quit_cmd[] = "QUIT\n",
- ok_rsp[] = "+OK", /* Response string keys */
- err_rsp[] = "-ERR";
-
- #define OK_RSP_LEN 3
- #define ERR_RSP_LEN 4
-
- static int
- domailbox(int argc,char *argv[],void *p) {
- if(argc < 2 && mailbox_name[0] != '\0')
- tprintf("%s\n",mailbox_name);
- else
- sprintf(mailbox_name,"%.18s",argv[1]);
- return 0;
- }
-
- static int
- domailhost(int argc,char *argv[],void *p) {
- int32 n;
-
- if(argc < 2) {
- tprintf("%s\n",inet_ntoa(mailhost));
- }
- else {
- if((n = resolve(argv[1])) == 0) {
- tprintf(Badhost,argv[1]);
- return 1;
- } else {
- mailhost = n;
- }
- }
- return 0;
- }
-
- static int
- popkick(int argc,char *argv[],void *p) {
- return (poptick());
- }
-
- static int
- doquiet(int argc,char *argv[],void *p) {
- return setintrc(&Popquiet,"POP3 quiet",argc,argv,0,3);
- }
-
- static struct timer popcli_t;
-
- static int
- dotimer(int argc,char *argv[],void *p) {
- if(argc < 2) {
- tprintf("POP3 timer %lu/%lu s\n",
- read_timer(&popcli_t)/1000L,dur_timer(&popcli_t)/1000L);
- }
- else {
- stop_timer(&popcli_t);
- popcli_t.func = (void (*)())poptick; /* what to call on timeout */
- popcli_t.arg = NULLCHAR; /* dummy value */
- set_timer(&popcli_t,atol(argv[1])*1000L); /* set timer duration */
- start_timer(&popcli_t); /* and fire it up */
- }
- return 0;
- }
-
- static int
- douserdata(int argc,char *argv[],void *p) {
- if (argc < 2 && username[0] != '\0')
- tprintf("%s\n",username);
- else if (argc != 3) {
- tputs("Usage: pop3 userdata <username> <password>\n");
- return 1;
- }
- else {
- sprintf(username,"%.18s",argv[1]);
- sprintf(password,"%.18s",argv[2]);
- }
- return 0;
- }
-
- int
- dopop3(int argc,char *argv[],void *p) {
- struct cmds Popcmds[] = {
- "mailbox", domailbox, 0, 0, NULLCHAR,
- "mailhost", domailhost, 0, 0, NULLCHAR,
- "kick", popkick, 0, 0, NULLCHAR,
- "quiet", doquiet, 0, 0, NULLCHAR,
- "timer", dotimer, 0, 0, NULLCHAR,
- "userdata", douserdata, 0, 0, NULLCHAR,
- NULLCHAR,
- };
- return subcmd(Popcmds,argc,argv,p);
- }
-
- static int
- poptick()
- {
- int error = 0;
-
- if (ccb == NULLCCB) {
- /* Don't start if any of the required parameters have not been specified */
- if (mailhost == 0) {
- tputs("POP3 Mailhost not set\n");
- error = 1;
- }
- if (mailbox_name[0] == '\0') {
- tputs("POP3 Mailbox not set\n");
- error = 1;
- }
- if (username[0] == '\0' || password[0] == '\0') {
- tputs("POP3 Username and/or password not set\n");
- error = 1;
- }
- if(error == 0) {
- if ((ccb = (struct pop3_ccb *)mxallocw(sizeof(struct pop3_ccb))) == NULLCCB) {
- tputs("Unable to allocate CCB\n");
- error = 1;
- } else {
- stop_timer(&popcli_t);
- newproc("POP3 Client",1024,pop_send,0,ccb,NULL,0);
- }
- }
- }
- else {
- start_timer(&popcli_t);
- }
- return error;
- }
-
- static void
- pop_send(int unused,void *cb1,void *p) {
- struct sockaddr_in fsocket;
- FILE *mf;
- char *cp;
-
- fsocket.sin_family = AF_INET;
- fsocket.sin_addr.s_addr = mailhost;
- fsocket.sin_port = IPPORT_POP3;
-
- ccb->socket = socket(AF_INET,SOCK_STREAM,0);
- sockmode(ccb->socket,SOCK_ASCII);
-
- if (connect(ccb->socket,(char *)&fsocket,SOCKSIZE) != -1) {
- log(ccb->socket,"POP3 connect");
- ccb->state = CALL;
- ccb->msg_no = 1;
- ccb->messages = 0;
-
- for(;;) {
-
- if(ccb->state == ERROR)
- break;
-
- if (ccb->state == EXIT) {
- if (ccb->messages != 0) {
- if (copymail(Mailspool,mailbox_name,&ccb->buf[0],BUF_LEN,mf) == 0) {
- unlink(Workfile_name);
- if (Popquiet < 2)
- tprintf("New mail for %s from mailhost <%s> at %s%s",
- mailbox_name, inet_ntoa(mailhost), ctime(&currtime),
- (Popquiet < 1) ? "\007" : "");
-
- if (Popquiet == 2)
- log(ccb->socket,"POP3 new mail <%s>",inet_ntoa(mailhost));
- }
- else
- ccb->state = ERROR;
- }
- break;
- }
-
- if ( recvline(ccb->socket,ccb->buf,BUF_LEN) == -1) {
- ccb->state = ERROR;
- break;
- }
- rip(ccb->buf);
-
- switch(ccb->state) {
- case CALL:
- if (strncmp(ccb->buf,ok_rsp,OK_RSP_LEN) == 0) {
- usprintf(ccb->socket,user_cmd,username);
- ccb->state = PASS;
- } else {
- ccb->state = ERROR;
- }
- break;
-
- case PASS:
- if (strncmp(ccb->buf,ok_rsp,OK_RSP_LEN) == 0) {
- usprintf(ccb->socket,pass_cmd,password);
- ccb->state = STAT;
- } else {
- ccb->state = EXIT;
- }
- break;
-
- case STAT:
- if (strncmp(ccb->buf,ok_rsp,OK_RSP_LEN) == 0) {
- usputs(ccb->socket,stat_cmd);
- ccb->state = XFER;
- } else {
- ccb->state = EXIT;
- }
- break;
-
- case XFER:
- if (strncmp(ccb->buf,ok_rsp,OK_RSP_LEN) == 0) {
- cp = ccb->buf;
- while (*cp++ != ' ');
- ccb->messages = atoi(cp); /* get number of messages in the folder */
- if (ccb->messages > 0) {
- while (*cp++ != ' ');
- ccb->bytes = atol(cp); /* get folder size */
- usprintf(ccb->socket,retr_cmd,ccb->msg_no);
- ccb->state = RETR;
- if ( (mf = open_file(Workfile_name,"a+",0,1)) == NULLFILE) {
- ccb->state = ERROR;
- break;
- }
- fseek(mf,0,SEEK_END);
- }
- else {
- ccb->state = EXIT;
- }
- }
- else {
- ccb->state = EXIT; /* EXIT because we have not send a DELE cmd */
- }
- break;
-
- case RETR:
- if (strncmp(ccb->buf,ok_rsp,OK_RSP_LEN) == 0) {
- if ( recvmail(ccb,mf) == -1 ) {
- ccb->state = ERROR;
- }
- else {
- usprintf(ccb->socket,del_cmd,ccb->msg_no);
- ccb->state = DELE;
- }
- }
- else {
- if (strncmp(ccb->buf,err_rsp,ERR_RSP_LEN) == 0) {
- if (++ccb->msg_no > ccb->messages)
- ccb->state = EXIT;
- else
- usprintf(ccb->socket,retr_cmd,ccb->msg_no);
- }
- else {
- ccb->state = ERROR; /* don't send a QUIT cmd ==> UPDATE STATE */
- }
- }
- break;
-
- case DELE:
- if (++ccb->msg_no > ccb->messages)
- ccb->state = EXIT;
- else {
- usprintf(ccb->socket,retr_cmd,ccb->msg_no);
- ccb->state = RETR;
- }
- break;
-
- default:
- break;
- } /* end switch */
- } /* end for(;;) */
-
- if (mf != NULLFILE)
- fclose(mf);
-
- if (ccb->state == EXIT) {
- usprintf(ccb->socket,quit_cmd);
- recvline(ccb->socket,ccb->buf,BUF_LEN);
- }
- log(ccb->socket,"POP3 daemon exiting" );
- }
- else {
- log(ccb->socket,"POP3 Connect failed");
- }
-
- close_s(ccb->socket);
- xfree((char *)ccb);
- ccb = NULLCCB;
- start_timer(&popcli_t);
- return;
- }
-
- /* Receive message from socket, copying to file.
- * Returns number of lines received, -1 indicates error
- */
- static int
- recvmail(struct pop3_ccb *cp,FILE *fp) {
- int lines = 0;
- int first_line = 1;
-
- while (recvline(cp->socket,cp->buf,BUF_LEN) != -1) {
- char *p = cp->buf;
-
- if (first_line) {
- if(isNotSOM(&cp->buf[0]))
- fprintf(fp,"From POP3@%s at %s",inet_ntoa(mailhost),ptime(&currtime));
- first_line = 0;
- }
-
- /* check for end of message . or escaped .. */
- if (*p == '.') {
- if (*++p == '\n') {
- return lines;
- } else if ( *p != '.' ) {
- p--;
- }
- }
- /* Append to data file */
- fputs(p,fp);
- ++lines;
- }
- return -1;
- }
-
- /* Copy from the work file into the mailbox.
- * -1 indicates error
- */
- static int
- copymail(char *spoolarea,char *filename,char *buf,unsigned len,FILE *wfp) {
- FILE *mfp = NULLFILE;
-
- if (wfp == NULLFILE)
- return -1;
-
- while (mlock(spoolarea,filename)) {
- pause(10000L); /* 10 seconds */
- }
-
- sprintf(buf,"%s/%s.txt",spoolarea,filename);
- if ((mfp = fopen(buf,APPEND_TEXT)) == NULL) {
- tprintf("Can't open mailbox %s, new mail in %s\n", buf, Workfile_name);
- rmlock(spoolarea,filename);
- return -1;
- }
-
- rewind(wfp);
- while ( fgets(buf,len,wfp) != NULLCHAR ) {
- fputs(buf,mfp);
- pwait(NULL); /* give other processes time in long copy */
- }
- fclose(mfp);
- rmlock(spoolarea,filename);
- return 0;
- }
-
- #endif /* POP3_CLIENT */
-